﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Zhp.Auth.IService;
using Zhp.Auth.Model;
using Zhp.Cache;
using Zhp.Common.Appsetting;

namespace Zhp.Auth.Service
{
    public class OnlineService : IOnlineService
    {
        private readonly ICacheService _cache;

        public OnlineService(ICacheService cacheService, IConfiguration configuration)
        {
            _cache = cacheService;
        }

        /// <summary>
        /// 查询登录用户
        /// </summary>
        /// <returns></returns>
        public List<OnlineUserModel> GetOnlineUserList()
        {
            RemoveExpiresOnlineUser();

            var list = _cache.HashListGetAll<OnlineUserModel>(CacheKey.OnlineUser).ToList();
            foreach (var item in list)
            {
                item.AccessExpiresTime = GetAccessExpiresDate(item.CreateTime);
                item.RefreshExpiresTime = GetRefreshExpiresDate(item.CreateTime);
            }

            return list;
        }

        public List<OnlineUserModel> GetOnlineActiveUserList()
        {
            return _cache.HashListGetAll<OnlineUserModel>(CacheKey.OnlineActiveUser);
        }

        /// <summary>
        /// 判断用户是否登录
        /// </summary>
        /// <param name="tokenId"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public IsOnlineInfo IsOnline(string tokenId, string userId)
        {
            IsOnlineInfo isOnlineInfo = new IsOnlineInfo { IsOnline = false };

            var forcedOfflineUser = _cache.HashListGet<OnlineUserModel>(CacheKey.ForcedOfflineUser, tokenId);
            if (forcedOfflineUser != null)
            {
                RemoveOfflineUser(tokenId);

                isOnlineInfo.Message = "您的账号被系统强制登出！";
                return isOnlineInfo;
            }

            var otherDeviceUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OtherDeviceOfflineUser, tokenId);
            if (otherDeviceUser != null)
            {
                RemoveOfflineUser(tokenId);

                isOnlineInfo.Message = "被迫下线，当前账号已在其他客户端登录！";
                return isOnlineInfo;
            }

            var onlineUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OnlineUser, tokenId);
            if (onlineUser == null)
            {
                RemoveOfflineUser(tokenId);

                isOnlineInfo.Message = "登录过期，请重新登录！";
                return isOnlineInfo;
            }

            isOnlineInfo.IsOnline = true;
            isOnlineInfo.CurrentUserInfo = onlineUser;
            return isOnlineInfo;
        }

        /// <summary>
        /// 添加登录用户
        /// </summary>
        /// <param name="onlineUser"></param>
        public void AddOnlineUser(OnlineUserModel onlineUser)
        {
            RemoveExpiresOnlineUser();

            if (!IsMultiClientLogin())
            {
                MoveToOtherDeviceOfflineUser(onlineUser.UserId);
            }

            _cache.HashListSet(CacheKey.OnlineUser, x => x.TokenId, onlineUser);
        }

        /// <summary>
        /// 刷新登录用户
        /// </summary>
        /// <param name="onlineUser"></param>
        public void RefreshOnlineUser(OnlineUserModel onlineUser)
        {
            RemoveExpiresOnlineUser();

            _cache.HashListSet(CacheKey.OnlineUser, x => x.TokenId, onlineUser);
        }

        /// <summary>
        /// 移除登录用户
        /// </summary>
        /// <param name="tokenId"></param>
        public void RemoveOnlineUser(long tokenId)
        {
            _cache.HashListDelete(CacheKey.OnlineUser, tokenId.ToString());
        }

        /// <summary>
        /// 移除强退用户
        /// </summary>
        /// <param name="userId"></param>
        public void ForcedRemoveOfflineUser(long tokenId)
        {
            var onlineUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OnlineUser, tokenId.ToString());
            if (onlineUser != null)
            {
                _cache.HashListDelete(CacheKey.OnlineUser, tokenId.ToString());
                _cache.HashListSet(CacheKey.ForcedOfflineUser, x => x.TokenId, onlineUser);
            }
        }

        /// <summary>
        /// 异地设备登录账号时，将已登录的数据移动到缓存用于提示用户
        /// </summary>
        /// <param name="userId"></param>
        private void MoveToOtherDeviceOfflineUser(long userId)
        {
            var onlineUserList = _cache.HashListGetAll<OnlineUserModel>(CacheKey.OnlineUser);
            var lastLoginUser = onlineUserList.FirstOrDefault(x => x.UserId == userId);
            if (lastLoginUser != null)
            {
                _cache.HashListDelete(CacheKey.OnlineUser, lastLoginUser.TokenId.ToString());
                _cache.HashListSet(CacheKey.OtherDeviceOfflineUser, x => x.TokenId, lastLoginUser);
            }
        }

        /// <summary>
        /// 移除异地设备登录用户缓存数据和移除强退用户缓存数据
        /// </summary>
        /// <param name="tokenId"></param>
        private void RemoveOfflineUser(string tokenId)
        {
            _cache.HashListDelete(CacheKey.OtherDeviceOfflineUser, tokenId.ToString());
            _cache.HashListDelete(CacheKey.ForcedOfflineUser, tokenId.ToString());
        }

        /// <summary>
        /// 清理过期用户
        /// </summary>
        private void RemoveExpiresOnlineUser()
        {
            //由于缓存没有过期时间，需要把过期的token删除掉
            var onlineUserList = _cache.HashListGetAll<OnlineUserModel>(CacheKey.OnlineUser);
            var removeList = onlineUserList.Where(x => GetRefreshExpiresDate(x.CreateTime) <= DateTime.Now).Select(x => x.TokenId.ToString()).ToList();
            foreach (var item in removeList)
            {
                _cache.HashListDelete(CacheKey.OnlineUser, item);
            }
        }

        /// <summary>
        /// 是否多客户端登录
        /// </summary>
        /// <returns></returns>
        public bool IsMultiClientLogin()
        {
            var options = AppSettingHelper.GetOptions<SysDataOptions>();
            return options.MultiClientLogin;
        }

        /// <summary>
        /// 获取AccessToken过期时间
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public DateTime GetAccessExpiresDate(DateTime dateTime)
        {
            var jwtOptions = AppSettingHelper.GetOptions<JwtOptions>();
            return dateTime.AddMinutes(jwtOptions.Expires);
        }

        /// <summary>
        /// 获取RefreshToken过期时间
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public DateTime GetRefreshExpiresDate(DateTime dateTime)
        {
            var jwtOptions = AppSettingHelper.GetOptions<JwtOptions>();
            return dateTime.AddMinutes(jwtOptions.RefreshExpires);
        }
    }
}
